\section{CSS 选择符}
\label{CSS选择符}

CSS是一门用来描述HTML、XML文档在屏幕、纸张或者朗读设备等等上如何表现的语言，CSS使用选择符（selector）将样式（style）属性和文档中的特定元素（element）进行绑定。\cite{W3C，2011}随着相关技术的演进，CSS中的选择符也越来越丰富，功能也越来越强大。

\subsection{简单选择符}

简单选择符（Simple Selector）指的是选择符本身再无法分解，是构成组合选择符、群组选择符的选择符，这类选择符是CSS选择符的基础。

\subsubsection{类型选择符}

类型选择符（Type Selector），也叫做元素选择符，该选择符能代表文档树中的所有指定的元素。

\begin{lstlisting}
h1 {color:red}
\end{lstlisting}

上述规则将使文档中所有的h1元素字体颜色为红色。

\subsubsection{通配选择符}

通配选择符（Universal Selector），将选定所有元素。通常不建议使用通配选择符，因为它会遍历并命中文档中所有的元素，出于性能考虑，需酌情使用。

\begin{lstlisting}
* {color:red}
\end{lstlisting}

上述规则将使文档中所有元素的前景色为红色。

\subsubsection{属性选择符}

属性选择符（Attribute Selector）将选定那些拥有匹配属性的元素。具体如下表\ref{tab:属性选择符}：

\begin{table}[htbp]
  \centering
  \caption{属性选择符及其含义}
    \begin{tabularx}{\linewidth}{X|X}
    \toprule
    属性选择符   & 含义 \\
    \midrule
    E[foo]  & 选择具有“foo”属性的元素 \\
    \hline
    E[foo="bar"] & 选择具有“foo”属性并且属性值完全等于“bar”的元素 \\
    \hline
    E[foo\~{}="bar"] & 选择具有“foo”属性，且值中其中一个等于“bar”的E元素（包含只有一个值且该值等于“bar”的情况）。 \\
    \hline
    E[foo\^{}="bar"] & 选择具有“foo”属性，并且属性值以“bar”开头的元素 \\
    \hline
    E[foo\${}="bar"] & 选择具有“foo”属性，并且属性值以“bar”结尾的元素 \\
    \hline
    E[foo*="bar"] & 选择具有“foo”属性，并且属性值包含“bar”的元素 \\
    \hline
    E[foo|="en"] & 选择具有“foo”属性，属性值并且以“en”开头并用连接符"-"分隔的字符串的E元素 \\
    \bottomrule
    \end{tabularx}%
  \label{tab:属性选择符}%
\end{table}%

\subsubsection{类选择符}

类选择符（Class Selector）将选择那些class属性值为指定值的元素。

\begin{lstlisting}
.bar 			/*将选择所有具有class="bar"属性及值的元素*/
h1.bar		/*将选择具有class="bar"的所有h1元素*/
.bar.foo	/*将选择class值中同时包含bar、foo的元素*/
\end{lstlisting}

带有元素名称的类选择符和使用class属性的属性选择符是等价的。如div.value 就等同于div[class~=value]。

\subsubsection{ID选择符}

ID选择符（ID Selector）将选择ID属性等于指定值的元素。按照W3C标准，ID属性在DOM中的值应该是唯一的。

\begin{lstlisting}
#bar 			/*将选择所有具有id="bar"属性值的元素*/
h1#bar		/*将选择具有id="bar"的h1元素*/
\end{lstlisting}

\subsection{简单选择符之伪类选择符}

伪类（pseudo-class）的概念是指那些不在文档树中或者不能使用其他简单选择符选择的内容。伪类以“：”开头，后面跟随伪类名称。根据类别不同，伪类选择符又分为：链接伪类选择符、用户行为伪类选择符、目标伪类选择符、语言伪类选择符、UI元素伪类选择符、结构伪类选择符、否定伪类选择符等。由于伪类选择符内容较多，虽然其从概念上将还是简单选择符，我们单独阐述。

\subsubsection{链接伪类选择符}

浏览器通常会将未访问的超级链接和访问过的超级链接加以区分，CSS提供了:link和:visited链接伪类选择符用以区别它们。

\begin{description}
	\item [:link] :link伪类将应用于那些没有被访问过的内容。
	\item [:visited] :visited伪类将应用于那些已经被访问过的内容。
\end{description}

\subsubsection{用户行为伪类选择符}

浏览器通常会在用户交互时用不同形式来表现交互状态。CSS使用以下三个伪类用以和用户交互：

\begin{description}
	\item [:hover] 该伪类选择符表示用户将鼠标（或其他交互设备）移动到元素之上时的状态。
	\item [:active] 该伪类表示用户激活（如点击）元素时的状态。
	\item [:focus] 该伪类表示获得焦点（如键盘输入、鼠标点击）时的状态。
\end{description}

\subsubsection{目标伪类选择符}

有时URI只需资源内部的某个部分，这种类型的URI的尾部含有数字标记“\#”,在“\#”之后是锚点识别符（也叫片段识别符）。例如下例中的section2：

\begin{lstlisting}
http://example.com/html/top.html#section2
\end{lstlisting}

使用:target伪类选择符，就可以对资源内部中片段识别符（如上例中section2）对应的元素设置样式。

\subsubsection{语言伪类选择符}

语言伪类选择符能对特定lang属性的元素设置样式。如：

\begin{lstlisting}
html:lang(zh) /*选中lang属性值为zh的html元素*/
\end{lstlisting}

\subsubsection{UI元素伪类选择符}

UI元素伪类选择符可以针对UI元素的状态进行选择。

\begin{description}
	\item [:enabled] 选择UI元素中处于enabled状态的元素。
	\item [:disabled] 选择UI元素中处于disabled状态的元素。
	\item [:checked] 使用:checked伪类选择符，可以选择被用户切换到选中状态radio、checkbox等元素。
\end{description}

\subsubsection{结构伪类选择符}
结构伪类选择符基于文档树中元素的父子兄弟关系进行选择。

\begin{description}
	\item [:root] 表示文档的根元素，在HTML4中，该选择符将始终选择html元素。
	\item [:nth-child()] 代表同一父级元素的第N个元素。如：
		\begin{lstlisting}
		tr:nth-child(2n+1) /* 表示表格中的奇数行 */
		tr:nth-child(odd)  /* 同上 */
		tr:nth-child(2n+0) /* 表示表格中的偶数行 */
		tr:nth-child(even) /* 同上 */
		tr:nth-child(5)		 /* 表示表格中的第5行 */
		\end{lstlisting}
	\item [:nth-last-child()] 表示在同一父元素中，从后往前计算的第N个元素。
	\item [:nth-of-type()] 表示同类型兄弟元素中的第N个元素。
	\item [:nth-last-of-type()] 表示同类型兄弟元素中，从后往前计算的第N个元素。
	\item [:first-child] 表示同一个父元素中的第一个子元素。
	\item [:last-child] 表示同一个父元素中的最后一个子元素。
	\item [:first-of-type] 表示同类型兄弟元素中的第一个元素。
	\item [:last-of-type] 表示同类型兄弟元素中的最后一个元素。
	\item [:only-child] 匹配父元素仅有的一个子元素。
	\item [:only-of-type] 匹配同类型中的唯一的一个同级兄弟元素。
	\item [:empty] 匹配没有任何子元素（包括text节点）的元素。
\end{description}

\subsubsection{否定伪类选择符}

否定伪类选择符:not(X)，将匹配不含有X选择符的元素。例如：

\begin{lstlisting}
.demo li:not(:last-child) { border-bottom: 1px solid #ddd; }
\end{lstlisting}

上述规则将匹配给定列表项（除最后一项之外），使其有一条红色的下划线。

\subsection{伪元素选择符}
伪元素能创造出HTML语言无法创造的抽象元素，如段落首行、首字母、元素前、元素后等等。伪元素选择符以“::”开始，\footnote{CSS3将伪对象选择符前面的单个冒号(:)修改为双冒号(::)用以区别伪类选择符，但以前的写法仍然有效。}后面跟元素元素名称。

\begin{description}
	\item [::first-line] 设置元素内的第一行的样式。此伪元素仅作用于块元素。
	\item [::first-letter] 设置对象内的第一个字符的样式。此伪对象仅作用于块对象。
	\item [::before] 设置在对象前（依据对象树的逻辑结构）发生的内容。和content属性一起使用，并且必须定义content属性。
	\item [::after] 设置在对象后（依据对象树的逻辑结构）发生的内容。和content属性一起使用，并且必须定义content属性。
\end{description}

\subsection{组合选择符}

组合选择符能根据文档树中选择符所代表的父子兄弟关系进行更加准确的选择，其在实际工作中使用率很高。

\subsubsection{后代选择符}
两个简单选择符之间用空格组合在一起，就表示后代选择符，如：

\begin{lstlisting}
h1 em
\end{lstlisting}
表示选择位于h1元素中的em元素。

\subsubsection{子元素选择符}
子元素选择符使用“>”将两个简单选择符组合在一起，选择具有父子关系的子元素。不同于后代选择符，子元素选择符只能命中子元素，而不能命中孙辈。例如：

\begin{lstlisting}
.demo > div
\end{lstlisting}

表示选择class为demo的元素中的div子元素。

\subsubsection{相邻选择符}

两个元素用“+”连接在一起，如E+F，表示选择出现在E元素之后的F元素。

\subsubsection{兄弟选择符}

两个元素用“\~{}”连接在一起，如E\~{}F，兄弟选择符会命中所有符合条件的兄弟元素，而不强制是紧邻的元素。

\subsection{群组选择符}

在CSS中，使用“,”将选择符连接在一起，表示这些选择符共享相同的样式声明。例如：

\begin{lstlisting}
h1,h2,h3 {color : red;}
\end{lstlisting}

上述例子表示，h1、h2、h3元素的颜色都为红色。群组选择符，能降低CSS样式书写时的重复规则，提高开发效率。

\subsection{选择符优先级别}

层级样式表之所以叫作“层级”，就是规则可以重叠、可以嵌套。这样就产生了新的问题：当规则重叠时，CSS是如何决定采用哪个规则呢？总的原则是，最后出现的规则有效，越具体的选择符优先。

选择符的优先级别计算规则如下：

\begin{enumerate}
	\item 计算选择符中的ID选择符数量(= a)。
	\item 计算选择符中的类选择符、属性选择符和伪类选择符数量(= b)。
	\item 计算元素选择符和伪元素选择符的数量(= c)
	\item 忽略通配选择符。
	\item 将a-b-c的值连接在一起就得到选择符的优先级别，该值越大，优先级别越高。
\end{enumerate}

例如：
\begin{lstlisting}
*               /* a=0 b=0 c=0 -> specificity =   0 */
LI              /* a=0 b=0 c=1 -> specificity =   1 */
UL LI           /* a=0 b=0 c=2 -> specificity =   2 */
UL OL+LI        /* a=0 b=0 c=3 -> specificity =   3 */
H1 + *[REL=up]  /* a=0 b=1 c=1 -> specificity =  11 */
UL OL LI.red    /* a=0 b=1 c=3 -> specificity =  13 */
LI.red.level    /* a=0 b=2 c=1 -> specificity =  21 */
#x34y           /* a=1 b=0 c=0 -> specificity = 100 */
#s12:not(FOO)   /* a=1 b=0 c=1 -> specificity = 101 */
\end{lstlisting}
